home *** CD-ROM | disk | FTP | other *** search
- /*
- * beztwist.c 17-Sep-88
- *
- * Display some twisting cubic Bezier curves. Works with all 3
- * resolution modes of the Atari ST. Originally written for
- * Turbo C by (?).
- *
- * note: this uses Bresenham's line drawing algorithm to write
- * directly to screen memory. it uses Physbase to find this. it
- * will work on all three "normal" screen resolutions (320x200x16 low,
- * 640x200x4 med, and 640x400x2 high). it will probably not work with
- * other monitors.
- *
- * compile: gcc -mshort -O -o bez.ttp bez.c
- */
-
- #ifndef lint
- static char *rcsid = "$Id: bez.c,v 1.2 1992/05/09 19:05:46 rosenkra Exp $";
- #endif
-
- /*
- * $Log: bez.c,v $
- * Revision 1.2 1992/05/09 19:05:46 rosenkra
- * port to gnu C. nothing else done except reformatting source.
- * major change was rand initialization. now uses time rather than
- * 200 hz timer (which had bad code anyway). also changed INFO and
- * BEZIER structs to typedefs.
- *
- */
-
- #include <stdlib.h> /* for rand,srand */
- #include <time.h> /* for time */
- #include <osbind.h> /* for Bios,Xbios,Gemdos calls */
-
- #define WORD_BITS 16 /* screen "word" this size in bits */
-
- #define low_res 0 /* screen resolution */
- #define med_res 1
- #define hi_res 2
-
- #define HI_PLANES 1 /* for hi rez */
- #define HI_XMIN 0
- #define HI_XMAX 639
- #define HI_YMIN 0
- #define HI_YMAX 399
- #define HI_XWIDTH 640 /* (HI_XMAX - HI_XMIN + 1) */
- #define HI_YHEIGTH 400 /* (HI_YMAX - HI_YMIN + 1) */
- #define HI_WPLINE 40 /* (HI_PLANES * HI_XWIDTH / WORD_BITS)*/
- #define HI_COLORS 2 /* (1 << HI_PLANES) */
-
- #define ME_PLANES 2 /* for med rez */
- #define ME_XMIN 0
- #define ME_XMAX 639
- #define ME_YMIN 0
- #define ME_YMAX 199
- #define ME_XWIDTH 640 /* (ME_XMAX - ME_XMIN + 1) */
- #define ME_YHEIGTH 200 /* (ME_YMAX - ME_YMIN + 1) */
- #define ME_WPLINE 80 /* (ME_PLANES * ME_XWIDTH / WORD_BITS)*/
- #define ME_COLORS 4 /* (1 << ME_PLANES) */
-
- #define LO_PLANES 4 /* for lo rez */
- #define LO_XMIN 0
- #define LO_XMAX 319
- #define LO_YMIN 0
- #define LO_YMAX 199
- #define LO_XWIDTH (LO_XMAX - LO_XMIN + 1)
- #define LO_YHEIGTH (LO_YMAX - LO_YMIN + 1)
- #define LO_WPLINE (LO_PLANES * LO_XWIDTH / WORD_BITS)
- #define LO_COLORS (1 << LO_PLANES)
-
- #define CHANGE 0x0f /* how often to change colors */
- #define NQ 10 /* length of FIFO queue */
- #define MAXNQ 50 /* max number of lines (-l) */
- #define FLAT 32L /* for area convergence */
- #define CONSOLE 2 /* BIOS console */
-
- #define BITS 5
- #define SCALE (1 << BITS)
- #define SCALE2 (1 << (BITS-1))
-
-
- /*
- * screen info
- */
- typedef struct
- {
- unsigned int *i_screen;
- int i_res;
- long i_planes,
- i_wpline;
- unsigned int i_color,
- i_colmask;
- long i_xmax,
- i_ymax;
- long i_maxarea;
- } info_t;
-
-
- /*
- * curve info
- */
- typedef struct
- {
- long b_x[4];
- long b_y[4];
- int b_active;
-
- } bez_t;
-
-
-
- int grayscale = 0; /* for color gray palette */
-
-
- /*
- * local functions
- */
- void bezier ();
- void draw_line ();
- void rand_init ();
- void set_color ();
- void usage ();
-
-
-
-
- /*------------------------------*/
- /* main */
- /*------------------------------*/
- void main (argc, argv)
- int argc;
- char *argv[];
- {
-
- /*
- * Show some randomly twisting bezier curves.
- */
-
- info_t info; /* screen info */
- bez_t list[MAXNQ]; /* list of curves */
- bez_t *q; /* current one */
- long dx[4],
- dy[4];
- long *p;
- unsigned int colr;
- int i,
- j,
- k,
- n;
- long loop,
- flat;
- int lines,
- change;
- int tmp1, tmp2;
-
-
-
-
- /*
- * initialize rand ()
- */
- rand_init ();
-
-
-
- /*
- * where HARDWARE screen is. we write there directly for speed
- */
- info.i_screen = Physbase ();
-
-
-
- /*
- * get resolution
- */
- info.i_res = Getrez ();
-
-
-
- /*
- * all this does is clear the screen...
- */
- Setscreen (-1L, -1L, (int) info.i_res);
-
-
-
- /*
- * cmdline args.
- * first is number of curves (def = NQ)
- * second is loop counter. if +ve, only draw loop times. if -ve,
- * loop infinite.
- * third is convergence factor. the larger it is, the faster it
- * converges. try 50-1000.
- */
- lines = NQ;
- loop = -1,
- flat = 0;
- change = CHANGE;
-
- argc--, argv++;
- while (argc)
- {
- if (**argv != '-')
- {
- usage ();
-
- exit (0);
- }
- switch (*(*argv+1))
- {
- case 'h':
- case 'H':
- usage ();
- exit (0);
- case 'l':
- case 'L':
- argc--, argv++;
- lines = atoi (*argv);
- if (lines > MAXNQ)
- lines = MAXNQ;
- break;
- case 'n':
- case 'N':
- argc--, argv++;
- loop = atoi (*argv);
- break;
- case 'f':
- case 'F':
- argc--, argv++;
- flat = atoi (*argv);
- break;
- case 'c':
- case 'C':
- argc--, argv++;
- change = atoi (*argv);
- break;
- case 'g':
- case 'G':
- grayscale = 1;
- break;
- }
- argc--, argv++;
- }
- if (loop < 1)
- loop = -1;
- if (change < 1)
- change = CHANGE;
-
-
-
- /*
- * save color pal and reset to new one
- */
- set_color ((int) info.i_res, 1);
-
-
-
- /*
- * fill in info struct based on resolution
- */
- switch (info.i_res)
- {
- case hi_res:
- info.i_xmax = HI_XMAX;
- info.i_ymax = HI_YMAX;
- info.i_planes = HI_PLANES;
- info.i_wpline = HI_WPLINE;
- info.i_maxarea = (flat >= 1 ? flat : FLAT) * SCALE * SCALE;
- info.i_colmask = HI_COLORS - 1;
- colr = HI_COLORS - 1;
- break;
-
- case med_res:
- info.i_xmax = ME_XMAX;
- info.i_ymax = ME_YMAX;
- info.i_planes = ME_PLANES;
- info.i_wpline = ME_WPLINE;
- info.i_maxarea = (flat >= 1 ? flat : (3 * FLAT) / 4) * SCALE * SCALE;
- info.i_colmask = ME_COLORS - 1;
- colr = ME_COLORS - 1;
- break;
-
- case low_res:
- info.i_xmax = LO_XMAX;
- info.i_ymax = LO_YMAX;
- info.i_planes = LO_PLANES;
- info.i_wpline = LO_WPLINE;
- info.i_maxarea = (flat >= 1 ? flat : FLAT / 2) * SCALE * SCALE;
- info.i_colmask = LO_COLORS - 1;
- colr = LO_COLORS - 1;
- break;
-
- default:
- exit (-1);
- }
-
-
-
- /*
- * initialize
- */
- for (i = 1; i < lines; i++)
- list[i].b_active = 0;
-
-
-
- /*
- * init things...loop is to make an initial surface (4 pts)
- */
- i = 0;
- q = &(list[0]);
- q->b_active = 1;
-
- for (k = 0; k < 4; k++)
- {
- tmp1 = rand ();
- tmp2 = (int) info.i_xmax;
- q->b_x[k] = (long) (tmp1 % tmp2);
- tmp1 = rand ();
- tmp2 = (int) info.i_ymax;
- q->b_y[k] = (long) (tmp1 % tmp2);
-
- n = (rand () & 15) - 7;
- if (n == 0)
- n = 1;
- else if (n == 8)
- n = -1;
- dx[k] = n;
-
- n = (rand () & 15) - 7;
- if (n == 0)
- n = 1;
- else if (n == 8)
- n = -1;
- dy[k] = n;
- }
-
-
-
- /*
- * do it. loop starts out -1 unless there is a cmdline arg so it
- * does this until a key is pressed
- */
- while (loop--)
- {
- /*
- * draw the current line...
- */
- info.i_color = colr;
- bezier (&info,
- (long)(q->b_x[0] * SCALE + SCALE2),
- (long)(q->b_y[0] * SCALE + SCALE2),
- (long)(q->b_x[1] * SCALE + SCALE2),
- (long)(q->b_y[1] * SCALE + SCALE2),
- (long)(q->b_x[2] * SCALE + SCALE2),
- (long)(q->b_y[2] * SCALE + SCALE2),
- (long)(q->b_x[3] * SCALE + SCALE2),
- (long)(q->b_y[3] * SCALE + SCALE2));
-
-
- /*
- * j is last one, i is next one (q -> next)
- */
- j = i;
- i = (i + 1) % lines;
- q = &(list[i]);
-
-
- /*
- * if next one is active, it was drawn already so undraw it
- */
- if (q->b_active)
- {
- info.i_color = 0;
- bezier (&info,
- (long)(q->b_x[0] * SCALE + SCALE2),
- (long)(q->b_y[0] * SCALE + SCALE2),
- (long)(q->b_x[1] * SCALE + SCALE2),
- (long)(q->b_y[1] * SCALE + SCALE2),
- (long)(q->b_x[2] * SCALE + SCALE2),
- (long)(q->b_y[2] * SCALE + SCALE2),
- (long)(q->b_x[3] * SCALE + SCALE2),
- (long)(q->b_y[3] * SCALE + SCALE2));
- }
-
-
- /*
- * is this needed???
- */
- q->b_active = 1;
-
-
- /*
- * set up points for next one...
- */
- for (k = 0; k < 4; k++)
- {
- p = &(q->b_x[k]);
- *p = list[j].b_x[k] + dx[k];
- if (*p < 0)
- {
- *p += 8;
- dx[k] = -dx[k];
- }
- else if (*p > info.i_xmax)
- {
- *p -= 8;
- dx[k] = -dx[k];
- }
-
- p = &(q->b_y[k]);
- *p = list[j].b_y[k] + dy[k];
- if (*p < 0)
- {
- *p += 8;
- dy[k] = -dy[k];
- }
- else if (*p > info.i_ymax)
- {
- *p -= 8;
- dy[k] = -dy[k];
- }
- }
-
-
- /*
- * every change times thru change color and direction...
- */
- if ((loop & change) == 0)
- {
- /*
- * change direction
- */
- k = rand () & 3;
- n = (rand () & 15) - 7;
- if (n == 0)
- n = 1;
- else if (n == 8)
- n = -1;
- if (rand () & 1)
- dx[k] = n;
- else
- dy[k] = n;
-
- /*
- * change color
- */
- colr = (rand () % info.i_colmask) + 1;
-
- loop = -1;
- }
-
- /*
- * exit if any key pressed, set to finish
- */
- if (Bconstat (CONSOLE))
- loop = 0;
- }
-
-
-
- /*
- * clear key press
- */
- while (Bconstat (CONSOLE))
- (void) Bconin (CONSOLE);
-
-
-
- /*
- * set screen colors back...
- */
- set_color ((int) info.i_res, 0);
-
-
- exit (0);
- }
-
-
-
-
- /*------------------------------*/
- /* bezier */
- /*------------------------------*/
- void bezier (pinfo, x0, y0, x1, y1, x2, y2, x3, y3)
- info_t *pinfo;
- long x0;
- long y0;
- long x1;
- long y1;
- long x2;
- long y2;
- long x3;
- long y3;
- {
-
- /* bezier()
- *
- * Draw the cubic (2d) Bezier curve specified by P0, P1, P2 and P3
- * by subdividing it recursively into sub-curves until it
- * can be approximated smoothly by straight line segments.
- * We use fixed point arithmetic to achieve increased precision
- * in coordinate computations. The control points have been
- * scaled with SCALE and 0.5 has been added to the coordinates
- * so that we can feed rounded coordinate values to draw_line().
- */
-
- long v1x,
- v1y,
- v2x,
- v2y,
- v3x,
- v3y;
- long vcp1,
- vcp2,
- vcp3,
- area;
- long mid_x,
- mid_y;
- int code;
-
-
-
- /*
- * Stop the recursion when the size of the area covered
- * by the convex hull of the Bezier curve is less than or
- * equal to pinfo->i_maxarea.
- */
-
-
-
- /*
- * First, compute direction vectors
- */
- v3x = x3 - x0;
- v3y = y3 - y0;
- v2x = x2 - x0;
- v2y = y2 - y0;
- v1x = x1 - x0;
- v1y = y1 - y0;
-
-
-
- /*
- * Then, compute vector cross products.
- */
- code = 0;
- if ((vcp1 = v3x * v2y - v2x * v3y) < 0)
- code += 4;
- if ((vcp2 = v3x * v1y - v1x * v3y) < 0)
- code += 2;
- if ((vcp3 = v2x * v1y - v1x * v2y) < 0)
- code += 1;
-
-
-
- /*
- * Finally, compute size of area covered by convex hull
- *
- * We actually compute 2*area, but that doesn't matter much.
- */
- switch (code)
- {
- case 0:
- case 2:
- case 5:
- case 7:
- area = vcp1 + vcp3;
- break;
- case 1:
- case 6:
- area = vcp2 - vcp3;
- break;
- case 3:
- case 4:
- area = vcp1 - vcp2;
- break;
- default:
- return;
- }
-
- if (code & 4)
- area = -1 * area;
-
-
-
- /*
- * converged?
- */
- if (area <= pinfo->i_maxarea)
- {
- /*
- * Yes. Stop recursion and draw a line from P0 to P3.
- *
- * Rescale and round coordinates before
- * feeding them to draw_line()
- */
- draw_line (pinfo,
- ((long) x0) >> BITS,
- ((long) y0) >> BITS,
- ((long) x3) >> BITS,
- ((long) y3) >> BITS);
-
- return;
- }
- else
- {
- /*
- * No. Area is still too big, so subdivide the curve into
- * two sub-curves and draw these recursively.
- */
- mid_x = (long) (x0 + (3 * x1) + (3 * x2) + x3) >> 3;
- mid_y = (long) (y0 + (3 * y1) + (3 * y2) + y3) >> 3;
-
- bezier (pinfo,
- (long) x0,
- (long) y0,
- (long) (x0 + x1) >> 1,
- (long) (y0 + y1) >> 1,
- (long) (x0 + (2 * x1) + x2) >> 2,
- (long) (y0 + (2 * y1) + y2) >> 2,
- (long) mid_x,
- (long) mid_y);
-
- bezier (pinfo,
- (long) mid_x,
- (long) mid_y,
- (long) (x1 + (2 * x2) + x3) >> 2,
- (long) (y1 + (2 * y2) + y3) >> 2,
- (long) (x2 + x3) >> 1,
- (long) (y2 + y3) >> 1,
- (long) x3,
- (long) y3);
-
- return;
- }
- }
-
-
-
-
- /*------------------------------*/
- /* draw_line */
- /*------------------------------*/
- void draw_line (pinfo, x_from, y_from, x_to, y_to)
- register info_t *pinfo;
- register long x_from;
- long y_from;
- long x_to;
- long y_to;
- {
-
- /*
- * Draw a line from point (x_from, y_from) to point (x_to, y_to).
- * Use Bresenham's line drawing algorithm with incremental
- * screen address computation and inline plotting. (Fast!)
- */
-
- register unsigned int *scrn;
- register unsigned int or_mask;
- register unsigned int and_mask;
- register unsigned int colr;
- long del_x,
- del_y,
- inc_left,
- inc_lup;
- long count,
- dist,
- offset;
- int flag;
-
-
-
-
- /*
- * find motion
- */
- del_y = y_to - y_from;
-
- if ((del_x = x_to - x_from) < 0)
- {
- del_x = -del_x;
- del_y = -del_y;
- x_from = x_to;
- y_from = y_to;
- }
-
- if (del_y < 0)
- {
- offset = -(pinfo->i_wpline);
- del_y = -del_y;
- }
- else
- {
- offset = pinfo->i_wpline;
- }
-
- if (del_x < del_y)
- {
- flag = 1;
- count = del_y;
- del_y = del_x;
- del_x = count;
- }
- else
- {
- flag = 0;
- count = del_x;
- }
-
-
-
- /*
- * this calculates the word in screen memory where we wish to plot
- */
- scrn = (unsigned int *) (pinfo->i_screen +
- (y_from * pinfo->i_wpline) + ((x_from >> 4) * pinfo->i_planes));
-
-
-
- /*
- * now set the mask for the actual pixel in the word...
- */
- or_mask = 0x8000 >> (int) (x_from & 0x0000000FL);
- inc_left = 2 * del_y;
- dist = inc_left - del_x;
- inc_lup = dist - del_x;
- colr = pinfo->i_color;
-
-
-
- /*
- * loop until all points in the segment are "drawn"
- */
- for (;;)
- {
- and_mask = ~or_mask;
-
- switch (pinfo->i_res)
- {
- case low_res:
- if (colr & 8)
- scrn[3] |= or_mask;
- else
- scrn[3] &= and_mask;
- if (colr & 4)
- scrn[2] |= or_mask;
- else
- scrn[2] &= and_mask;
- /*FALL THRU...*/
- case med_res:
- if (colr & 2)
- scrn[1] |= or_mask;
- else
- scrn[1] &= and_mask;
- /*FALL THRU...*/
- case hi_res:
- if (colr & 1)
- scrn[0] |= or_mask;
- else
- scrn[0] &= and_mask;
- /*FALL THRU...*/
- default:
- break;
- }
-
-
-
- /*
- * we done?
- */
- if (count <= 0)
- break;
- count--;
-
-
- if (dist >= 0)
- {
- /*
- * Move 1 pixel 'left' and 'up'.
- */
- dist += inc_lup;
- or_mask >>= 1;
- scrn += offset;
- }
- else
- {
- /*
- * Move 1 pixel 'left'.
- */
- dist += inc_left;
- if (flag)
- scrn += offset;
- else
- or_mask >>= 1;
- }
-
-
-
- /*
- * wraparound
- */
- if (or_mask == 0x0000)
- {
- scrn += pinfo->i_planes;
- or_mask = 0x8000;
- }
- }
-
- return;
- }
-
-
-
-
- /*------------------------------*/
- /* rand_init */
- /*------------------------------*/
- void rand_init ()
- {
-
- /*
- * set rand by getting current time via time
- */
- long seed;
-
- seed = (long) time ((time_t *) 0);
- srand ((int) seed);
- }
-
-
-
-
- /*-----------------------------*/
- /* set_color */
- /*-----------------------------*/
-
- int old_palette[16];
-
- int hi_palette[16] =
- { /*RGB*/
- 0x000, /* black (gackground) */
- 0x777, /* white */
-
- 0x444, 0x444, 0x444, 0x444, 0x444, 0x444, 0x444,
- 0x444, 0x444, 0x444, 0x444, 0x444, 0x444, 0x444
- };
-
- int med_palette[16] =
- { /*RGB*/
- 0x000, /* black (gackground) */
- 0x700, /* red */
- 0x070, /* green */
- 0x007, /* blue */
-
- 0x444, 0x444, 0x444, 0x444, 0x444, 0x444,
- 0x444, 0x444, 0x444, 0x444, 0x444, 0x444
- };
-
- int med_gray_palette[16] = /* alternate for gray-scale... */
- { /*RGB*/
- 0x000, /* black (gackground) */
- 0x777,
- 0x444,
- 0x222,
-
- 0x444, 0x444, 0x444, 0x444, 0x444, 0x444,
- 0x444, 0x444, 0x444, 0x444, 0x444, 0x444
- };
-
- int lo_palette[16] =
- { /*RGB*/
- 0x000, /* black (gackground) */
- 0x700, /* red */
- 0x070, /* green */
- 0x007, /* blue */
- 0x077, /* cyan */
- 0x770, /* yellow */
- 0x707, /* magenta */
- 0x777, /* white */
- 0x742, /* orange */
- 0x517, /* purple */
- 0x520, /* brown */
- 0x444, /* gray */
- 0x744, /* lt red */
- 0x574, /* lt green */
- 0x467, /* lt blue */
- 0x666 /* lt gray */
- };
-
- int lo_gray_palette[16] = /* alternate for gray-scale... */
- { /*RGB*/
- 0x000, /* black (gackground) */
- 0x777, /* white */
- 0x666,
- 0x555,
- 0x444,
- 0x333,
- 0x222,
- 0x111,
- 0x777,
- 0x666,
- 0x555,
- 0x444,
- 0x333,
- 0x222,
- 0x111,
- 0x777
- };
-
- void set_color (res, opt)
- int res;
- int opt; /* 1=set, 0=reset to orig */
- {
- int i;
-
- if (opt)
- {
- /*
- * save user's palette and load our own
- */
- for (i = 0; i < 16; i++)
- old_palette[i] = Setcolor (i, -1);
-
- switch (res)
- {
- case 0: /* low */
- if (grayscale)
- Setpalette (lo_gray_palette);
- else
- Setpalette (lo_palette);
- break;
-
- case 1: /* med */
- if (grayscale)
- Setpalette (med_gray_palette);
- else
- Setpalette (med_palette);
- break;
-
- case 2: /* hi */
- Setpalette (hi_palette);
- break;
- }
- }
- else
- {
- /*
- * reset to user's palette before exit
- */
- Setpalette (old_palette);
- }
-
- return;
-
- }
-
-
-
-
- /*-----------------------------*/
- /* usage */
- /*-----------------------------*/
- void usage ()
- {
- Cconws ("\r\nUsage: bez [-l lines] [-n times] [-f converge] [-c changefreq] [-gray]\n\r");
- Cconws ("\r\n\n\nAny key...");
- while (!(Bconstat (CONSOLE)))
- ;
- (void) Bconin (CONSOLE);
- Cconws ("\r\n");
- }
-
-